package model.rotations;

import model.cubos.Adesivo;
import model.cubos.CuboMagico;
import model.matrizes.MatrizBidimensional;

/**
 * Esta classe possui as possíveis rotações do {@link CuboMagico}.
 * 
 * @author Joeffison Silverio de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 12/11/11 08:28
 */
public class RotationsImpl implements Rotations {

        @Override
        public void U(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                
                // Todos os cubos tem apenas 4 cores.
                Adesivo[] linha_0 = cube[0][0];
                Adesivo[] linha_1 = cube[1][0];
                Adesivo[] linha_2 = cube[2][0];
                Adesivo[] linha_3 = cube[3][0];
                //Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.
                
                
                /* Trocando as linhas. */
                cube[0][0] = linha_1;
                cube[1][0] = linha_2;
                cube[2][0] = linha_3;
                cube[3][0] = linha_0;
                
                MatrizBidimensional.transposta(cube[4]); // Finalmente aplicando conceitos que pensamos não ter aplicações... xP
                MatrizBidimensional.espelharColunas(cube[4]);
                
        }

        @Override
        public void U_(CuboMagico cubo) {
                U(cubo);
                U(cubo);
                U(cubo);
        }

        @Override
        public void U2(CuboMagico cubo) {
                U(cubo);
                U(cubo);
        }

        @Override
        public void D(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                
                // Todos os cubos tem apenas 4 cores.
                Adesivo[] linha_0 = cube[0][cube[0].length-1]; // Últimas linhas do cubo.
                Adesivo[] linha_1 = cube[1][cube[0].length-1];
                Adesivo[] linha_2 = cube[2][cube[0].length-1];
                Adesivo[] linha_3 = cube[3][cube[0].length-1];
                
                //Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.
                
                
                /* Trocando as linhas. */
                cube[0][cube[0].length-1] = linha_3;
                cube[1][cube[0].length-1] = linha_0;
                cube[2][cube[0].length-1] = linha_1;
                cube[3][cube[0].length-1] = linha_2;
                
                MatrizBidimensional.transposta(cube[5]);
                MatrizBidimensional.espelharColunas(cube[5]);
        }

        @Override
        public void D_(CuboMagico cubo) {
                D(cubo);
                D(cubo);
                D(cubo);
        }

        @Override
        public void D2(CuboMagico cubo) {
                D(cubo);
                D(cubo);
        }

        @Override
        public void F(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCoresColunas = {1, 3};
                Adesivo[][] colunas = new Adesivo[2][dim];
                Adesivo[][] linhas = new Adesivo[2][dim];
                for (int i = 0; i<interacaoCoresColunas.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i==0? 0:2)];
                        }
                }
                linhas[0] = cube[4][2];
                linhas[1] = cube[5][0];
                
                cube[1][0][0] = linhas[0][0];
                cube[1][1][0] = linhas[0][1];
                cube[1][2][0] = linhas[0][2];
                
                cube[3][0][2] = linhas[1][0];
                cube[3][1][2] = linhas[1][1];
                cube[3][2][2] = linhas[1][2];
                
                cube[4][2][0] = colunas[1][2];
                cube[4][2][1] = colunas[1][1];
                cube[4][2][2] = colunas[1][0];
                
                cube[5][0][0] = colunas[0][2];
                cube[5][0][1] = colunas[0][1];
                cube[5][0][2] = colunas[0][0];
                
                MatrizBidimensional.transposta(cube[0]);
                MatrizBidimensional.espelharColunas(cube[0]);
        }

        @Override
        public void F_(CuboMagico cubo) {
                F(cubo);
                F(cubo);
                F(cubo);
        }

        @Override
        public void F2(CuboMagico cubo) {
                F(cubo);
                F(cubo);
        }

        @Override
        public void B(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCoresColunas = {1, 3};
                Adesivo[][] colunas = new Adesivo[2][dim];
                Adesivo[][] linhas = new Adesivo[2][dim];
                for (int i = 0; i<interacaoCoresColunas.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i==0? 2:0)];
                        }
                }
                linhas[0] = cube[4][0];
                linhas[1] = cube[5][2];
                
                cube[1][0][2] = linhas[1][2];
                cube[1][1][2] = linhas[1][1];
                cube[1][2][2] = linhas[1][0];
                
                cube[3][0][0] = linhas[0][2];
                cube[3][1][0] = linhas[0][1];
                cube[3][2][0] = linhas[0][0];
                
                cube[4][0] = colunas[0];
                
                cube[5][2] = colunas[1];
                
                MatrizBidimensional.transposta(cube[2]);
                MatrizBidimensional.espelharColunas(cube[2]);
        }

        @Override
        public void B_(CuboMagico cubo) {
                B(cubo);
                B(cubo);
                B(cubo);
        }

        @Override
        public void B2(CuboMagico cubo) {
                B(cubo);
                B(cubo);
        }

        @Override
        public void R(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCores = {0, /*2,*/ 4, 5};
                Adesivo[][] colunas = new Adesivo[4][dim];
                for (int i = 0; i<interacaoCores.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCores[i]][j][dim-1];
                        }
                }
                for (int j = 0; j<dim; j++) {
                        colunas[colunas.length-1][j] = cube[2][j][0];
                }
                
                cube[0][0][2] = colunas[2][0];
                cube[0][1][2] = colunas[2][1];
                cube[0][2][2] = colunas[2][2];
                
                cube[4][0][2] = colunas[0][0];
                cube[4][1][2] = colunas[0][1];
                cube[4][2][2] = colunas[0][2];
                
                cube[5][0][2] = colunas[3][2];
                cube[5][1][2] = colunas[3][1];
                cube[5][2][2] = colunas[3][0];
                
                cube[2][0][0] = colunas[1][2];
                cube[2][1][0] = colunas[1][1];
                cube[2][2][0] = colunas[1][0];
                
                MatrizBidimensional.transposta(cube[1]);
                MatrizBidimensional.espelharColunas(cube[1]);
        }

        @Override
        public void R_(CuboMagico cubo) {
                R(cubo);
                R(cubo);
                R(cubo);
        }

        @Override
        public void R2(CuboMagico cubo) {
                R(cubo);
                R(cubo);
        }

        @Override
        public void L(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCores = {0, /*2,*/ 4, 5};
                Adesivo[][] colunas = new Adesivo[4][dim];
                for (int i = 0; i<interacaoCores.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCores[i]][j][0];
                        }
                }
                for (int j = 0; j<dim; j++) {
                        colunas[colunas.length-1][j] = cube[2][j][dim-1];
                }
                
                cube[0][0][0] = colunas[1][0];
                cube[0][1][0] = colunas[1][1];
                cube[0][2][0] = colunas[1][2];
                
                cube[5][0][0] = colunas[0][0];
                cube[5][1][0] = colunas[0][1];
                cube[5][2][0] = colunas[0][2];
                
                cube[4][0][0] = colunas[3][2];
                cube[4][1][0] = colunas[3][1];
                cube[4][2][0] = colunas[3][0];
                
                cube[2][0][2] = colunas[2][2];
                cube[2][1][2] = colunas[2][1];
                cube[2][2][2] = colunas[2][0];
                
                MatrizBidimensional.transposta(cube[3]);
                MatrizBidimensional.espelharColunas(cube[3]);
        }

        @Override
        public void L_(CuboMagico cubo) {
                L(cubo);
                L(cubo);
                L(cubo);
        }

        @Override
        public void L2(CuboMagico cubo) {
                L(cubo);
                L(cubo);
        }

        @Override
        public void executa(CuboMagico cubo, String[] operacoes) {
                for (String oper : operacoes) {
            switch (oper) {
                case "U":
                    U(cubo);
                    break;
                case "U_":
                    U_(cubo);
                    break;
                case "U2":
                    U2(cubo);
                    break;
                case "D":
                    D(cubo);
                    break;
                case "D_":
                    D_(cubo);
                    break;
                case "D2":
                    D2(cubo);
                    break;
                case "F":
                    F(cubo);
                    break;
                case "F_":
                    F_(cubo);
                    break;
                case "F2":
                    F2(cubo);
                    break;
                case "B":
                    B(cubo);
                    break;
                case "B_":
                    B_(cubo);
                    break;
                case "B2":
                    B2(cubo);
                    break;
                case "R":
                    R(cubo);
                    break;
                case "R_":
                    R_(cubo);
                    break;
                case "R2":
                    R2(cubo);
                    break;
                case "L":
                    L(cubo);
                    break;
                case "L_":
                    L_(cubo);
                    break;
                case "L2":
                    L2(cubo);
                    break;
                case "Z":
                    Z(cubo);
                    break;
                case "Z_":
                    Z_(cubo);
                    break;
                case "Z2":
                    Z2(cubo);
                    break;
                default:
                    break;
            }
                }
        }

        public void Z(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCores = {1, 3/*, 4, 5*/};
                Adesivo[][] colunas = new Adesivo[2][dim];
                Adesivo[][] linhas = new Adesivo[2][dim];
                for (int i = 0; i<interacaoCores.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCores[i]][j][1];
                        }
                }
                
                linhas[0] = cube[4][1];
                linhas[1] = cube[5][1];
                
                cube[1][0][1] = linhas[1][2];
                cube[1][1][1] = linhas[1][1];
                cube[1][2][1] = linhas[1][0];
                
                cube[3][0][1] = linhas[0][2];
                cube[3][1][1] = linhas[0][1];
                cube[3][2][1] = linhas[0][0];
                
                cube[4][1] = colunas[0];
                
                cube[5][1] = colunas[1];
                
                F_(cubo);
                B(cubo);
        }
        
        public void Z_(CuboMagico cubo) {
                Z(cubo);
                Z(cubo);
                Z(cubo);
        }
        
        public void Z2(CuboMagico cubo) {
                Z(cubo);
                Z(cubo);
        }

        public void X(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                int[] interacaoCores = {0, 2, 4, 5};
                Adesivo[][] colunas = new Adesivo[4][dim];
                for (int i = 0; i<interacaoCores.length; i++) {
                        for (int j = 0; j<dim; j++) {
                                colunas[i][j] = cube[interacaoCores[i]][j][1];
                        }
                }
                
                cube[0][0][1] = colunas[3][0];
                cube[0][1][1] = colunas[3][1];
                cube[0][2][1] = colunas[3][2];
                
                cube[2][0][1] = colunas[2][2];
                cube[2][1][1] = colunas[2][1];
                cube[2][2][1] = colunas[2][0];
                
                cube[4][0][1] = colunas[0][0];
                cube[4][1][1] = colunas[0][1];
                cube[4][2][1] = colunas[0][2];
                
                cube[5][0][1] = colunas[1][2];
                cube[5][1][1] = colunas[1][1];
                cube[5][2][1] = colunas[1][0];
                
                L_(cubo);
                R(cubo);
        }
        
        public void X_(CuboMagico cubo) {
                X(cubo);
                X(cubo);
                X(cubo);
        }
        
        public void X2(CuboMagico cubo) {
                X(cubo);
                X(cubo);
        }

        public void Y(CuboMagico cubo) {
                E_(cubo);
                D_(cubo);
                U(cubo);
        }

        public void E_(CuboMagico cubo) {
                Adesivo[][][] cube = cubo.getCubo();
                int dim = cube[0].length;
                Adesivo[][] linhas = new Adesivo[4][dim];
                for (int i = 0; i<4; i++) {
                        linhas[i] = cube[i][1];
                }
                
                cube[0][1] = linhas[1];
                cube[1][1] = linhas[2];
                cube[2][1] = linhas[3];
                cube[3][1] = linhas[0];
        }
        
        public void E(CuboMagico cubo) {
                E_(cubo);
                E_(cubo);
                E_(cubo);
        }
        
        public void E2(CuboMagico cubo) {
                E_(cubo);
                E_(cubo);
        }
        
        public void Y_(CuboMagico cubo) {
                Y(cubo);
                Y(cubo);
                Y(cubo);
        }
        
        public void Y2(CuboMagico cubo) {
                Y(cubo);
                Y(cubo);
        }

        
        
        
}